Začneme tým, že si do RStudia importujeme dáta. Ide o surové textové dáta, takže to nie je žiadny problém. Zvolíme import dát, zadáme cestu a prenesieme do nášho kódu:

hygdata_v3 <- read.csv("~/GitHub/HYG-Database/hygdata_v3.csv")
View(hygdata_v3)

Teraz už s nimi môžeme pracovať, najprv sa však pozrieme, ako sú usporiadané.

head(hygdata_v3)

Môžeme si všimnúť, že ide o pomerne komplexné dáta, ktoré sú bohaté okrem zaradenia do rôznych astronomických katalógov aj na údaje o relatívnej polohe a rýchlosti týchto vesmírnych objektov, ako aj o ich svietivosti a podobne. Máme teda na výber množstvo súvislostí, ktoré môžeme odhaľovať medzi jednotlivými parametrami.

Našou úplne prvou úlohou bude pozrieť sa, ako sú naše dáta v súbore rozdelené. Nebudeme sa trápiť s vykresľovaním jednotlivých charakteristík, radšej použijeme nástroje, ktoré sú v R už vbudované (summary). Zároveň by bolo ale fajn otestovať nedokonalosti v dátach, a ďalšiu informáciu nám môže poskytnúť aj modus, ktorý v bežnom summary nie je prítomný, a tak si ho pripravíme zvlášť a aplikujeme spolu so summary na naše dáta.

print(summary(hygdata_v3))
       id              hip               hd               hr                gl                  bf        
 Min.   :     0   Min.   :     1   Min.   :     1   Min.   :   2             :115813             :116516  
 1st Qu.: 29903   1st Qu.: 29565   1st Qu.: 46734   1st Qu.:2281     GJ 1001 :     1   41The1Ori :     3  
 Median : 59807   Median : 59172   Median :110382   Median :4567     GJ 1002 :     1   100    Her:     2  
 Mean   : 59807   Mean   : 59170   Mean   :114377   Mean   :4564     GJ 1003 :     1   12Omi Cap :     2  
 3rd Qu.: 89710   3rd Qu.: 88763   3rd Qu.:175849   3rd Qu.:6850     GJ 1004 :     1   17Sig CrB :     2  
 Max.   :119615   Max.   :120404   Max.   :358431   Max.   :9110     GJ 1005A:     1   19    Lyn :     2  
                  NA's   :1658     NA's   :20732    NA's   :110589   (Other) :  3796   (Other)   :  3087  
        proper             ra              dec               dist               pmra          
           :119468   Min.   : 0.000   Min.   :-89.782   Min.   :     0.0   Min.   :-4432.650  
 268 G. Cet:     1   1st Qu.: 6.217   1st Qu.:-36.421   1st Qu.:   115.1   1st Qu.:  -15.460  
 3C 273    :     1   Median :12.128   Median : -1.640   Median :   213.7   Median :   -1.680  
 82 G. Eri :     1   Mean   :12.095   Mean   : -1.985   Mean   :  8764.8   Mean   :   -1.312  
 96 G. Psc :     1   3rd Qu.:18.117   3rd Qu.: 31.519   3rd Qu.:   390.6   3rd Qu.:   12.180  
 Acamar    :     1   Max.   :23.999   Max.   : 89.569   Max.   :100000.0   Max.   : 6767.260  
 (Other)   :   141                                                                            
     pmdec                rv                 mag             absmag             spect      
 Min.   :-5813.00   Min.   :-386.9000   Min.   :-26.70   Min.   :-16.6800   K0     : 8569  
 1st Qu.:  -22.39   1st Qu.:   0.0000   1st Qu.:  7.65   1st Qu.:  0.1390   G5     : 6021  
 Median :   -5.76   Median :   0.0000   Median :  8.46   Median :  1.4950   A0     : 4943  
 Mean   :  -19.32   Mean   :  -0.2773   Mean   :  8.43   Mean   :  0.9921   F8     : 4366  
 3rd Qu.:    3.77   3rd Qu.:   0.0000   3rd Qu.:  9.17   3rd Qu.:  3.1590   G0     : 4237  
 Max.   : 9999.99   Max.   : 471.0000   Max.   : 21.00   Max.   : 19.6290   F5     : 3860  
                                                                            (Other):87618  
       ci                x                   y                   z                   vx            
 Min.   :-0.4000   Min.   :-99950.39   Min.   :-99979.25   Min.   :-99964.98   Min.   :-1.023e-01  
 1st Qu.: 0.3480   1st Qu.:   -89.02   1st Qu.:   -91.17   1st Qu.:  -107.54   1st Qu.:-1.034e-05  
 Median : 0.6160   Median :    -1.04   Median :    -1.24   Median :    -3.41   Median : 1.300e-07  
 Mean   : 0.7115   Mean   :  -234.85   Mean   :   -39.57   Mean   :  -231.90   Mean   :-2.891e-05  
 3rd Qu.: 1.0830   3rd Qu.:    86.27   3rd Qu.:    91.85   3rd Qu.:    94.97   3rd Qu.: 9.100e-06  
 Max.   : 5.4600   Max.   : 99982.37   Max.   : 99996.07   Max.   : 99862.51   Max.   : 1.023e-01  
 NA's   :1882                                                                                      
       vy                   vz                 rarad           decrad            pmrarad          
 Min.   :-1.023e-01   Min.   :-1.023e-01   Min.   :0.000   Min.   :-1.56700   Min.   :-2.149e-05  
 1st Qu.:-1.860e-06   1st Qu.:-1.998e-05   1st Qu.:1.628   1st Qu.:-0.63566   1st Qu.:-7.495e-08  
 Median : 1.182e-05   Median :-6.230e-06   Median :3.175   Median :-0.02862   Median :-8.140e-09  
 Mean   : 2.164e-04   Mean   :-1.566e-04   Mean   :3.167   Mean   :-0.03465   Mean   :-6.360e-09  
 3rd Qu.: 3.209e-05   3rd Qu.: 3.150e-06   3rd Qu.:4.743   3rd Qu.: 0.55011   3rd Qu.: 5.905e-08  
 Max.   : 1.023e-01   Max.   : 1.023e-01   Max.   :6.283   Max.   : 1.56328   Max.   : 3.281e-05  
                                                                                                  
    pmdecrad              bayer             flam             con             comp        comp_primary   
 Min.   :-2.818e-05          :118078   Min.   :  1.0    Cen    : 4222   Min.   :1.000   Min.   :     0  
 1st Qu.:-1.086e-07   Alp    :    80   1st Qu.: 14.0    UMa    : 3549   1st Qu.:1.000   1st Qu.: 29812  
 Median :-2.793e-08   Bet    :    77   Median : 31.5    Her    : 3383   Median :1.000   Median : 59628  
 Mean   :-9.366e-08   Eps    :    74   Mean   : 37.3    Cyg    : 3081   Mean   :1.005   Mean   : 59635  
 3rd Qu.: 1.828e-08   Del    :    71   3rd Qu.: 55.0    Hya    : 3027   3rd Qu.:1.000   3rd Qu.: 89453  
 Max.   : 5.007e-05   Eta    :    68   Max.   :140.0    Cet    : 2958   Max.   :3.000   Max.   :119615  
                      (Other):  1166   NA's   :116874   (Other):99394                                   
       base             lum                 var            var_min          var_max      
         :118527   Min.   :        0          :113624   Min.   :-1.33    Min.   :-1.52   
 GJ 1047 :     3   1st Qu.:        5   R      :    60   1st Qu.: 8.53    1st Qu.: 8.24   
 Gl  57.1:     3   Median :       22   S      :    52   Median : 9.85    Median : 9.65   
 Gl  60  :     3   Mean   :   354469   T      :    50   Mean   : 9.50    Mean   : 9.26   
 Gl 100  :     3   3rd Qu.:       77   W      :    39   3rd Qu.:10.71    3rd Qu.:10.49   
 Gl 106.1:     3   Max.   :409260660   U      :    37   Max.   :14.90    Max.   :13.70   
 (Other) :  1072                       (Other):  5752   NA's   :102623   NA's   :102623  

Ak si pozorne prezrieme zobrazené charakteristiky, môžeme si všimnúť, že v niektorých položkách sú prítomné outlieri. Keďže však ide o reálne objekty s objektívnymi vlastnosťami, nebudeme ich zatiaľ vyradzovať (napríklad lum - svietivosť ako násobok svietivosti Slnka). Určite však budeme musieť upraviť veľmi dôležitú položku dist - teda vzdialenosť hviezdy získanú na základe jej paralaxy (relatívnej zmeny polohy kvôli pozorovaniu z dvoch protiľahlých miest na obežnej dráhe Slnka). Ako si môžeme všimnúť, tretí kvartil zasahuje hlboko pod maximálnu hodnotu súboru. Keď sa pozrieme na modus tohto spojitého súboru, zistíme, že je to práve táto maximálna hodnota. Táto maximálna presná hodnota v spojitom spektre je dosť podozrivá:

modus <- function(v) 
{
   uniqv <- unique(v)
   uniqv[which.max(tabulate(match(v, uniqv)))]
}
modus(hygdata_v3[,10])
[1] 1e+05
hist(hygdata_v3[,10],xlab = "vzdialenosť(získaná pomocou paralaxy)",ylab = "počet výskytov",col = "darkblue",border = "blue")

Aha naozaj. Nájsť modus v spojitom súbore dát väčšinou znamená nejakú špecifickú vlastnosť značenia a histogram to potvrdzuje. V tomto bode si teda ešte raz prezrieme readme ku našej databáze. Naozaj. hodnota 100 000 znamená, že dáta chýbajú, alebo sú pochybné. Očistime naše dáta od tohoto znečistenia a pozrime sa na početnosti.

library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.2.1 --
<U+221A> ggplot2 3.2.1     <U+221A> purrr   0.3.3
<U+221A> tibble  2.1.3     <U+221A> dplyr   0.8.3
<U+221A> tidyr   1.0.0     <U+221A> stringr 1.4.0
<U+221A> readr   1.3.1     <U+221A> forcats 0.4.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
purified_1 <- filter(hygdata_v3,dist<=50000)
rest_1 <- filter(hygdata_v3, dist > 50000)
hist(purified_1[,10],xlab = "vzdialenosť(získaná pomocou paralaxy)",ylab = "počet výskytov",col = "darkblue",border = "blue")

hist(rest_1[,14],xlab = "magnitúda",ylab = "počet výskytov",col = "darkred",border = "gray")

Začnime s niečím jednoduchým. Radi by sme dokázali, že magnitúda (zdanlivá jasnosť hviezd) bude rásť (jej reprezentujúca číslica) so vzdialenosťou (prirodzený predpoklad v prípade homogénneho prostredia). Vynesme si teda tieto dve veličiny do grafu.

library(ggplot2)
ggplot(data = purified_1) +
geom_point(mapping = aes(x = dist, y = mag,size = 1/10^(mag),alpha = 1/100))

Z takéhoto grafu až tak veľa informácií nezískame. Dáta by bolo fajn si utriediť do nejakých skupín, a až takéto skupiny zobrazovať (a prípadne nastaviť vizuál podľa ich veľkostí). Poďme sa teda pustiť do našej prvej podúlohy - vyberme si z dát len zaujímavé položky a zoraďme ich podľa hodnoty.

hygdata_1 <- select(purified_1, id, proper, dist, rv, mag, absmag, con, lum)
hygdata_1

Teraz sa pokúsime nejako regulovať počet údajov. Jednotlivé objekty podľa vzdialenosti a magnitúdy zatriedime do vhodného počtu skupín. Využijeme zoradenie objektov vzostupne podľa vzdialenosťi, vykreslenie príslušnosti do skupín a funkciu cut.

dist
kat <- cut(hygdata_1$dist, 40, include.lowest=TRUE)
mutate(hygdata_1, kat)
hygdata_1
ggplot(data = hygdata_1) +
geom_point(mapping = aes(x = kat, y = mag, size = 1/10^(mag), alpha = 1/100), )

Ako si môžeme všimnúť, stále informačná hodnota takejto vizualizácie, nespĺňa naše požiadavky. Skúsime to inak: vizualizujme priamo závislosť vzdialenosti od magnitúry, ale príslušnosť ku jednotlivým vzialenostiam pre lepšiu prehľadnosť ofarbíme podľa rozdelenia spektra vzdialenosté do nastaviteľného počtu intervalov.

hygdata_1
kat <- cut(hygdata_1$dist, 25, include.lowest=TRUE, labels = FALSE)
mutate(hygdata_1, kat)
ggplot(data = hygdata_1) +
geom_point(mapping = aes(x = dist, y = mag, size = 1/10^(mag), alpha = 1/100), colour = kat)

Ako si môžeme všimnúť, vo funkcií cut sme použili labels = FALSE, pretože nechceme ručne zadávať potenciálne veľké množstvo názvov, ktoré nemajú informačnú hodnotu, len sú feed-om pre parameter colour pri kreslení grafu. To, že sme túto možnosť dali do kódu nám ale umožňuje voľne a nezáväzne adjustovať počet farebných hladín a počet “chlievikov”, ktoré zobrazujeme - vlastne to používame ako taký “kvázihistogram” - vidíme takto na našom grafe početnosti. Táto funkcia to delí na rovnaké podintervaly. Nám by pre vizualizáciu možno pomohlo, keby to delíme na kúsky s rovnakým počtom vzoriek - tak by sme získali informáciu o rozdelení našich dát a bolo by toto rozdelenie krásne vidno. Teraz sa to pokúsime spraviť. Hľadali sme možnosti až sme došli k jednoduchej variante príkazu cut, a to cut_number:

hygdata_1
kat <- cut_number(hygdata_1$dist, 20 , labels = FALSE)
mutate(hygdata_1, kat)
ggplot(data = hygdata_1) +
geom_point(mapping = aes(x = dist, y = mag, size = 1/1.1^(mag), alpha = 1/1000), colour = kat)

Teraz už sú dáta zobrazené pomerne prehľadne. Môžeme teda usúdiť, že náš predpoklad sa nepotvrdil. Vecou, ktorá je vďaka tejto vizualizácií najzrejmejšia, je rozdiel počtov hviezd v databáze pre jednotlivé vzdialenosti. Šírka stĺpcu (chlievika), ktorý obsahuje fixný počet hviezd sa so stúpajúcou vzdialenosťou zväčšuje - nie sme schopní detekovať všetky hviezdy (za predpokladu relatívnej homogenity rozmiestenenia hviezd vo vesmíre). Druhým viditeľným poznatkom je, že do vzdialenosti asi 50 parsekov sme schopní zachytiť aj objekty s veľmi malou zdanlivou magnitúdou. Potom ale počet takýchto objektov v databáze exponenciálne klesá. Tento pokles nie je spôsobený tým, že by vo vzdialenejších častiach menej jasné objekty neboli, ale tým, že ich nie sme schopní detekovať. V našej databáze teda tieto objekty nie sú. Teda ako to už býva, náš jednoduchý predpoklad “so stúpajúcou vzdialenosťou stúpa číslo magnitúdy” musíme korigovať ako “so stúpajúcou vzdialenosťou sme schopní zachytiť čoraz menej hviezd a žiadne s príliš veľkou magnitúdou (nízkou zdanlivou jasnosťou)”.

Druhým cieľom, ktorý by sme chceli splniť, je vykreslenie tvaru súhvezdí na oblohe podľa ich súradníc. Na takýto komplexnejšií problém využijeme fazety a identifikáciu podľa stĺpca con (skratka pre constellation). V prvom rade si z nášho komplexného dátového súboru vyberieme len položky, ktoré sú pre nás zaujímavé. Budeme postupovať analogicky ako v prvej časti.

hygdata_2 <- select(hygdata_v3, id, proper, mag, con, x, y, z, vx, vy, vz, rarad, decrad, pmrarad, pmdecrad)
hygdata_2 <- filter(hygdata_2,con!="")

Poďme sa pozrieť na rozdelenia jednotlivých súradníc - na základe tohoto sa rozhodneme, ktorú metódu vizualizácie zvolíme. Zároveň sa poďme pozrieť, koľko hodnôt môže nadobúdať kategorická premenná con - koľko je súhvezdí?

library(ggplot2)
ggplot(data.frame(hygdata_2$con), aes(x=hygdata_2$con), colour = hygdata_2$con ) +
  geom_bar()

Ako môžeme vidieť, Súhvezdí je trochu moc, aby sme ich mohli všetky vykresliť. Vyberieme si teda len niektoré z nich a tejto vzorke sa budeme venovať. Samozrejme, v prípade záujmu by sme nasledujúce postupy mohli použiť aj na iných ľubovoľných súhvezdiach. Poďme sa pozrieť na počty hviezd v niektorých súhvezdiach / zvoľme napríklad Pisces - Ryby a Leo - lev.

hygdata_2Psc<-filter(hygdata_2, con =="Psc") 
hist(hygdata_2Psc[,3],xlab = "magnitúda",ylab = "počet výskytov",col = "darkred",border = "gray")

hygdata_2Leo<-filter(hygdata_2, con=="Leo") 
hist(hygdata_2Leo[,3],xlab = "magnitúda",ylab = "počet výskytov",col = "darkblue",border = "gray")

Ako vidíme, počty hviezd v jednotlivých súhvezdiach sú vyššie, ako by bolo možné prehľadne zobraziť. Poďme teda odfiltrovať hviezdy, ktoré nie sú viditeľné voľným okom. Uvádza sa, že voľným okom je možné vidieť objekty s veľkosťou okolo 6 magnitúdy (http://dust.ess.uci.edu/ppr/ppr_Wea47.pdf). Použime tento predpoklad a odfiltrujme hviezdy, ktoré nie sú viditeľné voľným okom (po optimalizácií sme zvolili ešte nižšiu hodnotu magnitúdy cutoff):

hygdata_2
hygdata_2_vi <- filter(hygdata_2, mag<4.5)
hygdata_2_vi

A môžeme začať vykresľovať! Samozrejme, ešte zvoľme, ktoré súhvezdia vykreslíme. Tak spravme túto úlohu pre 12 znamení zverokruhu:

hygdata_2_vi
hygdata_2_vi_z <- filter(hygdata_2_vi, con =="Ari"|con =="Tau"|con =="Gem"|con =="Cnc"|con =="Leo"|con =="Vir"|con =="Lib"|con =="Sco"|con =="Sgr"|con =="Aqr"|con =="Psc"|con =="Cap")
hygdata_2_vi_z

A teraz už naozaj môžeme začať vykresľovať. Skúsme, ako to vôbec bude vyzerať pre jedno súhvezdie (dobre identifikovateľný Leo). Vykresľujeme jednotlivé súhvezdia podľa ich súradníc na nebeskej klenbe (najprv sme experimentovali s x, y a z súradnicami až pokým sme si neuvedomili ich význam v tejto databáze). Takto sú charakteristické tvary viditeľné:

hygdata_2_vi_leo <- filter(hygdata_2_vi_z, con =="Leo")
ggplot(data = hygdata_2_vi_leo) +
  geom_point(mapping = aes(x = hygdata_2_vi_leo$rarad, y = hygdata_2_vi_leo$decrad, size = 1/1.01^(hygdata_2_vi_leo$mag), alpha = 1))

Naozaj to funguje. Tvar súhvezdia, ktorý je bežne zobrazovaný, je zrkadlovo prevrátený (https://upload.wikimedia.org/wikipedia/commons/5/56/Leo_IAU.svg), ale v podstate ide o ten istý obrazec, teda sa nám podarilo vizualizovať jedno súhvezdie. Skúsme to spraviť pre všetky zvolené súhvezdia zo znamení zverokruhu. Ak volíme fazetové zobrazenie, je nutné nastaviť parameter scales ako voľný, pretože inak by sme nevideli nič (zlá mierka).

hygdata_2_vi_z
ggplot(data = hygdata_2_vi_z) +
  geom_point(mapping = aes(x = hygdata_2_vi_z$rarad, y = hygdata_2_vi_z$decrad, size = 1/100^(hygdata_2_vi_z$mag), alpha = 1), colour = "black", background=2) + 
facet_wrap(~con,scales = "free") + theme(panel.background = element_rect(fill = 'white', colour = 'white'))
Ignoring unknown parameters: background

Niektoré súhvezdia sú rozpoznateľné lepšie, iné horšie. Dalo by sa to zlepšiť napríklad iným nastavením filtračného parametra magnitúdy pre každé súhvezdie, podľa počtu hviezd. Niektoré súhvezdia totiž obsahujú aj hviezdy s menšou magnitúdou, ktoré sú ale význačné pre identifikáciu tvaru. My sa však ešte pozrieme na ďalšiu charakteristiku. Pozrieme sa, ako budú tieto súhvezdia vyzerať o 10 000 rokov. Takýto posun môžeme vizualizovať na základe radiálnych rýchlostí za rok, ktoré sú taktiež prítomné v databáze. Takže využime funkcie balíka dplyr:

hygdata_2_vi_z
hygdata_2_vi_z <- (mutate(hygdata_2_vi_z, rarad_10k = 100000*pmrarad + rarad, decrad_10k = 100000*pmdecrad + decrad ))

Teraz už zostáva tvar súhvezdí o 100 000 rokov len vykresliť. (nezabúdame, že je to pri uvažovanej konštantnej rýchlosti pohybu ako aj magnitúde, čo nie je pravidlom):

hygdata_2_vi_z
ggplot(data = hygdata_2_vi_z) +
  geom_point(mapping = aes(x = hygdata_2_vi_z$rarad_10k, y = hygdata_2_vi_z$decrad_10k, size = 1/10^(hygdata_2_vi_z$mag), alpha = 1), colour = "black", background=2) + 
facet_wrap(~con,scales = "free") + theme(panel.background = element_rect(fill = 'white', colour = 'white'))
Ignoring unknown parameters: background

Takto budú naše súhvezdia vyzerať o 100 000 rokov. Tvar niektorých zostane ešte rozpoznateľný, zatiaľ čo u iných bude deformovaný. (Pri parametri 1 000 000 rokov už sú súhvezdia nerozpoznateľné)

V tejto práci sme sa pokúsili využiť programovací jazyk R na organizáciu a vizualizáciu dát. Zamerali sme sa práve na tieto dve oblasti, pretože ide o najčastejšie používané typy práce s dátami. V prvom našom konkrétnom prípade sme formulovali hypotézu o vzťahu magnitúdy a vzdialenosti hviezdy, ktorú sme po preusporiadaní dát a ich vykreslení upravili. Dokázali sme tak, že vizualizácia a organizácia dát je veľmi dôležitá pre sformulovanie/potvrdenie/vyvrátenie vedeckej hypotézy. V druhej skôr zábavnej časti sme sa venovali vykresľovaniu zdanlivej polohy hviezd na oblohe podľa súhvezdí. Zredukovali sme výstupy z databázy, čo nám umožnilo rozumne vizualizovať dáta. Pridanou hodnotou bola prognóza, ktorá snáď budúcim astronómom uľahčí orientáciu na oblohe. :) Metódy by bolo možné zlepšiť použitím komplexnejších postupov.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KWmHEjW5lbWUgdMO9bSwgxb5lIHNpIGRvIFJTdHVkaWEgaW1wb3J0dWplbWUgZMOhdGEuIElkZSBvIHN1cm92w6kgdGV4dG92w6kgZMOhdGEsIHRha8W+ZSB0byBuaWUgamUgxb5pYWRueSBwcm9ibMOpbS4gWnZvbMOtbWUgaW1wb3J0IGTDoXQsIHphZMOhbWUgY2VzdHUgYSBwcmVuZXNpZW1lIGRvIG7DocWhaG8ga8OzZHU6DQoNCmBgYHtyfQ0KaHlnZGF0YV92MyA8LSByZWFkLmNzdigifi9HaXRIdWIvSFlHLURhdGFiYXNlL2h5Z2RhdGFfdjMuY3N2IikNClZpZXcoaHlnZGF0YV92MykNCmBgYA0KDQpUZXJheiB1xb4gcyBuaW1pIG3DtMW+ZW1lIHByYWNvdmHFpSwgbmFqcHJ2IHNhIHbFoWFrIHBvenJpZW1lLCBha28gc8O6IHVzcG9yaWFkYW7DqS4NCg0KYGBge3J9DQpoZWFkKGh5Z2RhdGFfdjMpDQpgYGANCg0KICBNw7TFvmVtZSBzaSB2xaFpbW7DusWlLCDFvmUgaWRlIG8gcG9tZXJuZSBrb21wbGV4bsOpIGTDoXRhLCBrdG9yw6kgc8O6IGJvaGF0w6kgb2tyZW0gemFyYWRlbmlhIGRvIHLDtHpueWNoIGFzdHJvbm9taWNrw71jaCBrYXRhbMOzZ292IGFqIG5hIMO6ZGFqZSBvIHJlbGF0w612bmVqIHBvbG9oZSBhIHLDvWNobG9zdGkgdMO9Y2h0byB2ZXNtw61ybnljaCBvYmpla3RvdiwgYWtvIGFqIG8gaWNoIHN2aWV0aXZvc3RpIGEgcG9kb2JuZS4gTcOhbWUgdGVkYSBuYSB2w71iZXIgbW5vxb5zdHZvIHPDunZpc2xvc3TDrSwga3RvcsOpIG3DtMW+ZW1lIG9kaGHEvm92YcWlIG1lZHppIGplZG5vdGxpdsO9bWkgcGFyYW1ldHJhbWkuDQoNCiAgTmHFoW91IMO6cGxuZSBwcnZvdSDDumxvaG91IGJ1ZGUgcG96cmllxaUgc2EsIGFrbyBzw7ogbmHFoWUgZMOhdGEgdiBzw7pib3JlIHJvemRlbGVuw6kuIE5lYnVkZW1lIHNhIHRyw6FwacWlIHMgdnlrcmVzxL5vdmFuw61tIGplZG5vdGxpdsO9Y2ggY2hhcmFrdGVyaXN0w61rLCByYWTFoWVqIHBvdcW+aWplbWUgbsOhc3Ryb2plLCBrdG9yw6kgc8O6IHYgUiB1xb4gdmJ1ZG92YW7DqSAoc3VtbWFyeSkuIFrDoXJvdmXFiCBieSBib2xvIGFsZSBmYWpuIG90ZXN0b3ZhxaUgbmVkb2tvbmFsb3N0aSB2IGTDoXRhY2gsIGEgxI9hbMWhaXUgaW5mb3Jtw6FjaXUgbsOhbSBtw7TFvmUgcG9za3l0bsO6xaUgYWogbW9kdXMsIGt0b3LDvSB2IGJlxb5ub20gc3VtbWFyeSBuaWUgamUgcHLDrXRvbW7DvSwgYSB0YWsgc2kgaG8gcHJpcHJhdsOtbWUgenZsw6HFocWlIGEgYXBsaWt1amVtZSBzcG9sdSBzbyBzdW1tYXJ5IG5hIG5hxaFlIGTDoXRhLg0KDQpgYGB7cn0NCnByaW50KHN1bW1hcnkoaHlnZGF0YV92MykpDQpgYGANCg0KICBBayBzaSBwb3pvcm5lIHByZXpyaWVtZSB6b2JyYXplbsOpIGNoYXJha3RlcmlzdGlreSwgbcO0xb5lbWUgc2kgdsWhaW1uw7rFpSwgxb5lIHYgbmlla3RvcsO9Y2ggcG9sb8W+a8OhY2ggc8O6IHByw610b21uw6kgb3V0bGllcmkuIEtlxI/FvmUgdsWhYWsgaWRlIG8gcmXDoWxuZSBvYmpla3R5IHMgb2JqZWt0w612bnltaSB2bGFzdG5vc8WlYW1pLCBuZWJ1ZGVtZSBpY2ggemF0aWHEviB2eXJhZHpvdmHFpSAobmFwcsOta2xhZCBsdW0gLSBzdmlldGl2b3PFpSBha28gbsOhc29ib2sgc3ZpZXRpdm9zdGkgU2xua2EpLiBVcsSNaXRlIHbFoWFrIGJ1ZGVtZSBtdXNpZcWlIHVwcmF2acWlIHZlxL5taSBkw7RsZcW+aXTDuiBwb2xvxb5rdSBkaXN0IC0gdGVkYSB2emRpYWxlbm9zxaUgaHZpZXpkeSB6w61za2Fuw7ogbmEgesOha2xhZGUgamVqIHBhcmFsYXh5IChyZWxhdMOtdm5laiB6bWVueSBwb2xvaHkga3bDtGxpIHBvem9yb3Zhbml1IHogZHZvY2ggcHJvdGnEvmFobMO9Y2ggbWllc3QgbmEgb2Jlxb5uZWogZHLDoWhlIFNsbmthKS4gQWtvIHNpIG3DtMW+ZW1lIHbFoWltbsO6xaUsIHRyZXTDrSBrdmFydGlsIHphc2FodWplIGhsYm9rbyBwb2QgbWF4aW3DoWxudSBob2Rub3R1IHPDumJvcnUuIEtlxI8gc2EgcG96cmllbWUgbmEgbW9kdXMgdG9odG8gc3Bvaml0w6lobyBzw7pib3J1LCB6aXN0w61tZSwgxb5lIGplIHRvIHByw6F2ZSB0w6F0byBtYXhpbcOhbG5hIGhvZG5vdGEuIFTDoXRvIG1heGltw6FsbmEgcHJlc27DoSBob2Rub3RhIHYgc3Bvaml0b20gc3Bla3RyZSBqZSBkb3PFpSBwb2RvenJpdsOhOg0KDQpgYGB7cn0NCm1vZHVzIDwtIGZ1bmN0aW9uKHYpIA0Kew0KICAgdW5pcXYgPC0gdW5pcXVlKHYpDQogICB1bmlxdlt3aGljaC5tYXgodGFidWxhdGUobWF0Y2godiwgdW5pcXYpKSldDQp9DQptb2R1cyhoeWdkYXRhX3YzWywxMF0pDQpoaXN0KGh5Z2RhdGFfdjNbLDEwXSx4bGFiID0gInZ6ZGlhbGVub3PFpSh6w61za2Fuw6EgcG9tb2NvdSBwYXJhbGF4eSkiLHlsYWIgPSAicG/EjWV0IHbDvXNreXRvdiIsY29sID0gImRhcmtibHVlIixib3JkZXIgPSAiYmx1ZSIpDQpgYGANCg0KICBBaGEgbmFvemFqLiBOw6Fqc8WlIG1vZHVzIHYgc3Bvaml0b20gc8O6Ym9yZSBkw6F0IHbDpMSNxaFpbm91IHpuYW1lbsOhIG5lamFrw7ogxaFwZWNpZmlja8O6IHZsYXN0bm9zxaUgem5hxI1lbmlhIGEgaGlzdG9ncmFtIHRvIHBvdHZyZHp1amUuIFYgdG9tdG8gYm9kZSBzaSB0ZWRhIGXFoXRlIHJheiBwcmV6cmllbWUgcmVhZG1lIGt1IG5hxaFlaiBkYXRhYsOhemUuIE5hb3phai4gaG9kbm90YSAxMDAgMDAwIHpuYW1lbsOhLCDFvmUgZMOhdGEgY2jDvWJhasO6LCBhbGVibyBzw7ogcG9jaHlibsOpLiBPxI1pc3RpbWUgbmHFoWUgZMOhdGEgb2QgdG9ob3RvIHpuZcSNaXN0ZW5pYSBhIHBvenJpbWUgc2EgbmEgcG/EjWV0bm9zdGkuDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpwdXJpZmllZF8xIDwtIGZpbHRlcihoeWdkYXRhX3YzLGRpc3Q8PTUwMDAwKQ0KcmVzdF8xIDwtIGZpbHRlcihoeWdkYXRhX3YzLCBkaXN0ID4gNTAwMDApDQpoaXN0KHB1cmlmaWVkXzFbLDEwXSx4bGFiID0gInZ6ZGlhbGVub3PFpSh6w61za2Fuw6EgcG9tb2NvdSBwYXJhbGF4eSkiLHlsYWIgPSAicG/EjWV0IHbDvXNreXRvdiIsY29sID0gImRhcmtibHVlIixib3JkZXIgPSAiYmx1ZSIpDQpoaXN0KHJlc3RfMVssMTRdLHhsYWIgPSAibWFnbml0w7pkYSIseWxhYiA9ICJwb8SNZXQgdsO9c2t5dG92Iixjb2wgPSAiZGFya3JlZCIsYm9yZGVyID0gImdyYXkiKQ0KYGBgDQoNCiAgWmHEjW5pbWUgcyBuaWXEjcOtbSBqZWRub2R1Y2jDvW0uIFJhZGkgYnkgc21lIGRva8OhemFsaSwgxb5lIG1hZ25pdMO6ZGEgKHpkYW5saXbDoSBqYXNub3PFpSBodmllemQpIGJ1ZGUgcsOhc8WlIChqZWogcmVwcmV6ZW50dWrDumNhIMSNw61zbGljYSkgc28gdnpkaWFsZW5vc8Wlb3UgKHByaXJvZHplbsO9IHByZWRwb2tsYWQgdiBwcsOtcGFkZSBob21vZ8Opbm5laG8gcHJvc3RyZWRpYSkuIFZ5bmVzbWUgc2kgdGVkYSB0aWV0byBkdmUgdmVsacSNaW55IGRvIGdyYWZ1Lg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChkYXRhID0gcHVyaWZpZWRfMSkgKw0KZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXN0LCB5ID0gbWFnLHNpemUgPSAxLzEwXihtYWcpLGFscGhhID0gMS8xMDApKQ0KYGBgDQoNCiAgWiB0YWvDqWhvdG8gZ3JhZnUgYcW+IHRhayB2ZcS+YSBpbmZvcm3DoWNpw60gbmV6w61za2FtZS4gRMOhdGEgYnkgYm9sbyBmYWpuIHNpIHV0cmllZGnFpSBkbyBuZWpha8O9Y2ggc2t1cMOtbiwgYSBhxb4gdGFrw6l0byBza3VwaW55IHpvYnJhem92YcWlIChhIHByw61wYWRuZSBuYXN0YXZpxaUgdml6dcOhbCBwb2TEvmEgaWNoIHZlxL5rb3N0w60pLiBQb8SPbWUgc2EgdGVkYSBwdXN0acWlIGRvIG5hxaFlaiBwcnZlaiBwb2TDumxvaHkgLSB2eWJlcm1lIHNpIHogZMOhdCBsZW4gemF1asOtbWF2w6kgcG9sb8W+a3kgYSB6b3JhxI9tZSBpY2ggcG9kxL5hIGhvZG5vdHkuDQoNCmBgYHtyfQ0KaHlnZGF0YV8xIDwtIHNlbGVjdChwdXJpZmllZF8xLCBpZCwgcHJvcGVyLCBkaXN0LCBydiwgbWFnLCBhYnNtYWcsIGNvbiwgbHVtKQ0KaHlnZGF0YV8xDQpgYGANCg0KICBUZXJheiBzYSBwb2vDunNpbWUgbmVqYWtvIHJlZ3Vsb3ZhxaUgcG/EjWV0IMO6ZGFqb3YuIEplZG5vdGxpdsOpIG9iamVrdHkgcG9kxL5hIHZ6ZGlhbGVub3N0aSBhIG1hZ25pdMO6ZHkgemF0cmllZGltZSBkbyB2aG9kbsOpaG8gcG/EjXR1IHNrdXDDrW4uIFZ5dcW+aWplbWUgem9yYWRlbmllIG9iamVrdG92IHZ6b3N0dXBuZSBwb2TEvmEgdnpkaWFsZW5vc8WlaSwgdnlrcmVzbGVuaWUgcHLDrXNsdcWhbm9zdGkgZG8gc2t1cMOtbiBhIGZ1bmtjaXUgY3V0Lg0KDQpgYGB7cn0NCmRpc3QNCmthdCA8LSBjdXQoaHlnZGF0YV8xJGRpc3QsIDQwLCBpbmNsdWRlLmxvd2VzdD1UUlVFKQ0KbXV0YXRlKGh5Z2RhdGFfMSwga2F0KQ0KaHlnZGF0YV8xDQpnZ3Bsb3QoZGF0YSA9IGh5Z2RhdGFfMSkgKw0KZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBrYXQsIHkgPSBtYWcsIHNpemUgPSAxLzEwXihtYWcpLCBhbHBoYSA9IDEvMTAwKSwgKQ0KYGBgDQoNCiAgQWtvIHNpIG3DtMW+ZW1lIHbFoWltbsO6xaUsIHN0w6FsZSBpbmZvcm1hxI1uw6EgaG9kbm90YSB0YWtlanRvIHZpenVhbGl6w6FjaWUsIG5lc3DEusWIYSBuYcWhZSBwb8W+aWFkYXZreS4gU2vDunNpbWUgdG8gaW5hazogdml6dWFsaXp1am1lIHByaWFtbyB6w6F2aXNsb3PFpSB2emRpYWxlbm9zdGkgb2QgbWFnbml0w7pyeSwgYWxlIHByw61zbHXFoW5vc8WlIGt1IGplZG5vdGxpdsO9bSB2emlhbGVub3N0aWFtIHByZSBsZXDFoWl1IHByZWjEvmFkbm9zxaUgb2ZhcmLDrW1lIHBvZMS+YSByb3pkZWxlbmlhIHNwZWt0cmEgdnpkaWFsZW5vc3TDqSBkbyBuYXN0YXZpdGXEvm7DqWhvIHBvxI10dSBpbnRlcnZhbG92Lg0KDQpgYGB7cn0NCmh5Z2RhdGFfMQ0Ka2F0IDwtIGN1dChoeWdkYXRhXzEkZGlzdCwgMjUsIGluY2x1ZGUubG93ZXN0PVRSVUUsIGxhYmVscyA9IEZBTFNFKQ0KbXV0YXRlKGh5Z2RhdGFfMSwga2F0KQ0KZ2dwbG90KGRhdGEgPSBoeWdkYXRhXzEpICsNCmdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzdCwgeSA9IG1hZywgc2l6ZSA9IDEvMTBeKG1hZyksIGFscGhhID0gMS8xMDApLCBjb2xvdXIgPSBrYXQpDQpgYGANCg0KICBBa28gc2kgbcO0xb5lbWUgdsWhaW1uw7rFpSwgdm8gZnVua2Npw60gY3V0IHNtZSBwb3XFvmlsaSBsYWJlbHMgPSBGQUxTRSwgcHJldG/FvmUgbmVjaGNlbWUgcnXEjW5lIHphZMOhdmHFpSBwb3RlbmNpw6FsbmUgdmXEvmvDqSBtbm/FvnN0dm8gbsOhenZvdiwga3RvcsOpIG5lbWFqw7ogaW5mb3JtYcSNbsO6IGhvZG5vdHUsIGxlbiBzw7ogZmVlZC1vbSBwcmUgcGFyYW1ldGVyIGNvbG91ciBwcmkga3Jlc2xlbsOtIGdyYWZ1LiBUbywgxb5lIHNtZSB0w7p0byBtb8W+bm9zxaUgZGFsaSBkbyBrw7NkdSBuw6FtIGFsZSB1bW/FvsWIdWplIHZvxL5uZSBhIG5lesOhdsOkem5lIGFkanVzdG92YcWlIHBvxI1ldCBmYXJlYm7DvWNoIGhsYWTDrW4gYSBwb8SNZXQgImNobGlldmlrb3YiLCBrdG9yw6kgem9icmF6dWplbWUgLSB2bGFzdG5lIHRvIHBvdcW+w612YW1lIGFrbyB0YWvDvSAia3bDoXppaGlzdG9ncmFtIiAtIHZpZMOtbWUgdGFrdG8gbmEgbmHFoW9tIGdyYWZlIHBvxI1ldG5vc3RpLiBUw6F0byBmdW5rY2lhIHRvIGRlbMOtIG5hIHJvdm5ha8OpIHBvZGludGVydmFseS4gTsOhbSBieSBwcmUgdml6dWFsaXrDoWNpdSBtb8W+bm8gcG9tb2hsbywga2VieSB0byBkZWzDrW1lIG5hIGvDunNreSBzIHJvdm5ha8O9bSBwb8SNdG9tIHZ6b3JpZWsgLSB0YWsgYnkgc21lIHrDrXNrYWxpIGluZm9ybcOhY2l1IG8gcm96ZGVsZW7DrSBuYcWhaWNoIGTDoXQgYSBib2xvIGJ5IHRvdG8gcm96ZGVsZW5pZSBrcsOhc25lIHZpZG5vLiBUZXJheiBzYSB0byBwb2vDunNpbWUgc3ByYXZpxaUuIEjEvmFkYWxpIHNtZSBtb8W+bm9zdGkgYcW+IHNtZSBkb8WhbGkgayBqZWRub2R1Y2hlaiB2YXJpYW50ZSBwcsOta2F6dSBjdXQsIGEgdG8gY3V0X251bWJlcjoNCg0KYGBge3J9DQpoeWdkYXRhXzENCmthdCA8LSBjdXRfbnVtYmVyKGh5Z2RhdGFfMSRkaXN0LCAyMCAsIGxhYmVscyA9IEZBTFNFKQ0KbXV0YXRlKGh5Z2RhdGFfMSwga2F0KQ0KZ2dwbG90KGRhdGEgPSBoeWdkYXRhXzEpICsNCmdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzdCwgeSA9IG1hZywgc2l6ZSA9IDEvMS4xXihtYWcpLCBhbHBoYSA9IDEvMTAwMCksIGNvbG91ciA9IGthdCkNCmBgYA0KDQogIFRlcmF6IHXFviBzw7ogZMOhdGEgem9icmF6ZW7DqSBwb21lcm5lIHByZWjEvmFkbmUuIE3DtMW+ZW1lIHRlZGEgdXPDumRpxaUsIMW+ZSBuw6HFoSBwcmVkcG9rbGFkIHNhIG5lcG90dnJkaWwuIFZlY291LCBrdG9yw6EgamUgdsSPYWthIHRlanRvIHZpenVhbGl6w6FjacOtIG5hanpyZWptZWrFoWlhLCBqZSByb3pkaWVsIHBvxI10b3YgaHZpZXpkIHYgZGF0YWLDoXplIHByZSBqZWRub3RsaXbDqSB2emRpYWxlbm9zdGkuIMWgw61ya2Egc3TEunBjdSAoY2hsaWV2aWthKSwga3RvcsO9IG9ic2FodWplIGZpeG7DvSBwb8SNZXQgaHZpZXpkIHNhIHNvIHN0w7pwYWrDumNvdSB2emRpYWxlbm9zxaVvdSB6dsOkxI3FoXVqZSAtIG5pZSBzbWUgc2Nob3Buw60gZGV0ZWtvdmHFpSB2xaFldGt5IGh2aWV6ZHkgKHphIHByZWRwb2tsYWR1IHJlbGF0w612bmVqIGhvbW9nZW5pdHkgcm96bWllc3RlbmVuaWEgaHZpZXpkIHZvIHZlc23DrXJlKS4NCiAgRHJ1aMO9bSB2aWRpdGXEvm7DvW0gcG96bmF0a29tIGplLCDFvmUgZG8gdnpkaWFsZW5vc3RpIGFzaSA1MCBwYXJzZWtvdiBzbWUgc2Nob3Buw60gemFjaHl0acWlIGFqIG9iamVrdHkgcyB2ZcS+bWkgbWFsb3UgemRhbmxpdm91IG1hZ25pdMO6ZG91LiBQb3RvbSBhbGUgcG/EjWV0IHRha8O9Y2h0byBvYmpla3RvdiB2IGRhdGFiw6F6ZSBleHBvbmVuY2nDoWxuZSBrbGVzw6EuIFRlbnRvIHBva2xlcyBuaWUgamUgc3DDtHNvYmVuw70gdMO9bSwgxb5lIGJ5IHZvIHZ6ZGlhbGVuZWrFocOtY2ggxI1hc3RpYWNoIG1lbmVqIGphc27DqSBvYmpla3R5IG5lYm9saSwgYWxlIHTDvW0sIMW+ZSBpY2ggbmllIHNtZSBzY2hvcG7DrSBkZXRla292YcWlLiBWIG5hxaFlaiBkYXRhYsOhemUgdGVkYSB0aWV0byBvYmpla3R5IG5pZSBzw7ouDQogIFRlZGEgYWtvIHRvIHXFviBiw712YSwgbsOhxaEgamVkbm9kdWNow70gcHJlZHBva2xhZCAic28gc3TDunBhasO6Y291IHZ6ZGlhbGVub3PFpW91IHN0w7pwYSDEjcOtc2xvIG1hZ25pdMO6ZHkiIG11c8OtbWUga29yaWdvdmHFpSBha28gInNvIHN0w7pwYWrDumNvdSB2emRpYWxlbm9zxaVvdSBzbWUgc2Nob3Buw60gemFjaHl0acWlIMSNb3JheiBtZW5laiBodmllemQgYSDFvmlhZG5lIHMgcHLDrWxpxaEgdmXEvmtvdSBtYWduaXTDumRvdSAobsOtemtvdSB6ZGFubGl2b3UgamFzbm9zxaVvdSkiLg0KDQogIERydWjDvW0gY2llxL5vbSwga3RvcsO9IGJ5IHNtZSBjaGNlbGkgc3BsbmnFpSwgamUgdnlrcmVzbGVuaWUgdHZhcnUgc8O6aHZlemTDrSBuYSBvYmxvaGUgcG9kxL5hIGljaCBzw7pyYWRuw61jLiBOYSB0YWvDvXRvIGtvbXBsZXhuZWrFoWnDrSBwcm9ibMOpbSB2eXXFvmlqZW1lIGZhemV0eSBhIGlkZW50aWZpa8OhY2l1IHBvZMS+YSBzdMS6cGNhIGNvbiAoc2tyYXRrYSBwcmUgY29uc3RlbGxhdGlvbikuIFYgcHJ2b20gcmFkZSBzaSB6IG7DocWhaG8ga29tcGxleG7DqWhvIGTDoXRvdsOpaG8gc8O6Ym9ydSB2eWJlcmllbWUgbGVuIHBvbG/Fvmt5LCBrdG9yw6kgc8O6IHByZSBuw6FzIHphdWrDrW1hdsOpLiBCdWRlbWUgcG9zdHVwb3ZhxaUgYW5hbG9naWNreSBha28gdiBwcnZlaiDEjWFzdGkuDQoNCmBgYHtyfQ0KaHlnZGF0YV8yIDwtIHNlbGVjdChoeWdkYXRhX3YzLCBpZCwgcHJvcGVyLCBtYWcsIGNvbiwgeCwgeSwgeiwgdngsIHZ5LCB2eiwgcmFyYWQsIGRlY3JhZCwgcG1yYXJhZCwgcG1kZWNyYWQpDQpoeWdkYXRhXzIgPC0gZmlsdGVyKGh5Z2RhdGFfMixjb24hPSIiKQ0KYGBgDQpQb8SPbWUgc2EgcG96cmllxaUgbmEgcm96ZGVsZW5pYSBqZWRub3RsaXbDvWNoIHPDunJhZG7DrWMgLSBuYSB6w6FrbGFkZSB0b2hvdG8gc2Egcm96aG9kbmVtZSwga3RvcsO6IG1ldMOzZHUgdml6dWFsaXrDoWNpZSB6dm9sw61tZS4gWsOhcm92ZcWIIHNhIHBvxI9tZSBwb3pyaWXFpSwga2/EvmtvIGhvZG7DtHQgbcO0xb5lIG5hZG9iw7pkYcWlIGthdGVnb3JpY2vDoSBwcmVtZW5uw6EgY29uIC0ga2/EvmtvIGplIHPDumh2ZXpkw60/DQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEuZnJhbWUoaHlnZGF0YV8yJGNvbiksIGFlcyh4PWh5Z2RhdGFfMiRjb24pLCBjb2xvdXIgPSBoeWdkYXRhXzIkY29uICkgKw0KICBnZW9tX2JhcigpDQpgYGANCg0KQWtvIG3DtMW+ZW1lIHZpZGllxaUsIFPDumh2ZXpkw60gamUgdHJvY2h1IG1vYywgYWJ5IHNtZSBpY2ggbW9obGkgdsWhZXRreSB2eWtyZXNsacWlLiBWeWJlcmllbWUgc2kgdGVkYSBsZW4gbmlla3RvcsOpIHogbmljaCBhIHRlanRvIHZ6b3JrZSBzYSBidWRlbWUgdmVub3ZhxaUuIFNhbW96cmVqbWUsIHYgcHLDrXBhZGUgesOhdWptdSBieSBzbWUgbmFzbGVkdWrDumNlIHBvc3R1cHkgbW9obGkgcG91xb5pxaUgYWogbmEgaW7DvWNoIMS+dWJvdm/Evm7DvWNoIHPDumh2ZXpkaWFjaC4gUG/Ej21lIHNhIHBvenJpZcWlIG5hIHBvxI10eSBodmllemQgdiBuaWVrdG9yw71jaCBzw7podmV6ZGlhY2ggLyB6dm/Evm1lIG5hcHLDrWtsYWQgUGlzY2VzIC0gUnlieSBhIExlbyAtIGxldi4gDQoNCmBgYHtyfQ0KaHlnZGF0YV8yUHNjPC1maWx0ZXIoaHlnZGF0YV8yLCBjb24gPT0iUHNjIikgDQpoaXN0KGh5Z2RhdGFfMlBzY1ssM10seGxhYiA9ICJtYWduaXTDumRhIix5bGFiID0gInBvxI1ldCB2w71za3l0b3YiLGNvbCA9ICJkYXJrcmVkIixib3JkZXIgPSAiZ3JheSIpDQpoeWdkYXRhXzJMZW88LWZpbHRlcihoeWdkYXRhXzIsIGNvbj09IkxlbyIpIA0KaGlzdChoeWdkYXRhXzJMZW9bLDNdLHhsYWIgPSAibWFnbml0w7pkYSIseWxhYiA9ICJwb8SNZXQgdsO9c2t5dG92Iixjb2wgPSAiZGFya2JsdWUiLGJvcmRlciA9ICJncmF5IikNCmBgYA0KDQpBa28gdmlkw61tZSwgcG/EjXR5IGh2aWV6ZCB2IGplZG5vdGxpdsO9Y2ggc8O6aHZlemRpYWNoIHPDuiB2ecWhxaFpZSwgYWtvIGJ5IGJvbG8gbW/Fvm7DqSBwcmVoxL5hZG5lIHpvYnJhemnFpS4gUG/Ej21lIHRlZGEgb2RmaWx0cm92YcWlIGh2aWV6ZHksIGt0b3LDqSBuaWUgc8O6IHZpZGl0ZcS+bsOpIHZvxL5uw71tIG9rb20uIFV2w6FkemEgc2EsIMW+ZSB2b8S+bsO9bSBva29tIGplIG1vxb5uw6kgdmlkaWXFpSBvYmpla3R5IHMgdmXEvmtvc8Wlb3Ugb2tvbG8gNiBtYWduaXTDumR5IChodHRwOi8vZHVzdC5lc3MudWNpLmVkdS9wcHIvcHByX1dlYTQ3LnBkZikuIFBvdcW+aW1lIHRlbnRvIHByZWRwb2tsYWQgYSBvZGZpbHRydWptZSBodmllemR5LCBrdG9yw6kgbmllIHPDuiB2aWRpdGXEvm7DqSB2b8S+bsO9bSBva29tIChwbyBvcHRpbWFsaXrDoWNpw60gc21lIHp2b2xpbGkgZcWhdGUgbmnFvsWhaXUgaG9kbm90dSBtYWduaXTDumR5IGN1dG9mZik6DQoNCmBgYHtyfQ0KaHlnZGF0YV8yDQpoeWdkYXRhXzJfdmkgPC0gZmlsdGVyKGh5Z2RhdGFfMiwgbWFnPDQuNSkNCmh5Z2RhdGFfMl92aQ0KYGBgDQoNCkEgbcO0xb5lbWUgemHEjWHFpSB2eWtyZXPEvm92YcWlISBTYW1venJlam1lLCBlxaF0ZSB6dm/Evm1lLCBrdG9yw6kgc8O6aHZlemRpYSB2eWtyZXNsw61tZS4gVGFrIHNwcmF2bWUgdMO6dG8gw7psb2h1IHByZSAxMiB6bmFtZW7DrSB6dmVyb2tydWh1Og0KDQpgYGB7cn0NCmh5Z2RhdGFfMl92aQ0KaHlnZGF0YV8yX3ZpX3ogPC0gZmlsdGVyKGh5Z2RhdGFfMl92aSwgY29uID09IkFyaSJ8Y29uID09IlRhdSJ8Y29uID09IkdlbSJ8Y29uID09IkNuYyJ8Y29uID09IkxlbyJ8Y29uID09IlZpciJ8Y29uID09IkxpYiJ8Y29uID09IlNjbyJ8Y29uID09IlNnciJ8Y29uID09IkFxciJ8Y29uID09IlBzYyJ8Y29uID09IkNhcCIpDQpoeWdkYXRhXzJfdmlfeg0KYGBgDQoNCkEgdGVyYXogdcW+IG5hb3phaiBtw7TFvmVtZSB6YcSNYcWlIHZ5a3Jlc8S+b3ZhxaUuIFNrw7pzbWUsIGFrbyB0byB2w7RiZWMgYnVkZSB2eXplcmHFpSBwcmUgamVkbm8gc8O6aHZlemRpZSAoZG9icmUgaWRlbnRpZmlrb3ZhdGXEvm7DvSBMZW8pLiBWeWtyZXPEvnVqZW1lIGplZG5vdGxpdsOpIHPDumh2ZXpkaWEgcG9kxL5hIGljaCBzw7pyYWRuw61jIG5hIG5lYmVza2VqIGtsZW5iZSAobmFqcHJ2IHNtZSBleHBlcmltZW50b3ZhbGkgcyB4LCB5IGEgeiBzw7pyYWRuaWNhbWkgYcW+IHBva8O9bSBzbWUgc2kgbmV1dmVkb21pbGkgaWNoIHbDvXpuYW0gdiB0ZWp0byBkYXRhYsOhemUpLiBUYWt0byBzw7ogY2hhcmFrdGVyaXN0aWNrw6kgdHZhcnkgdmlkaXRlxL5uw6k6DQoNCmBgYHtyfQ0KaHlnZGF0YV8yX3ZpX2xlbyA8LSBmaWx0ZXIoaHlnZGF0YV8yX3ZpX3osIGNvbiA9PSJMZW8iKQ0KZ2dwbG90KGRhdGEgPSBoeWdkYXRhXzJfdmlfbGVvKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gaHlnZGF0YV8yX3ZpX2xlbyRyYXJhZCwgeSA9IGh5Z2RhdGFfMl92aV9sZW8kZGVjcmFkLCBzaXplID0gMS8xLjAxXihoeWdkYXRhXzJfdmlfbGVvJG1hZyksIGFscGhhID0gMSkpDQpgYGANCg0KTmFvemFqIHRvIGZ1bmd1amUuIFR2YXIgc8O6aHZlemRpYSwga3RvcsO9IGplIGJlxb5uZSB6b2JyYXpvdmFuw70sIGplIHpya2FkbG92byBwcmV2csOhdGVuw70gKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvNS81Ni9MZW9fSUFVLnN2ZyksIGFsZSB2IHBvZHN0YXRlIGlkZSBvIHRlbiBpc3TDvSBvYnJhemVjLCB0ZWRhIHNhIG7DoW0gcG9kYXJpbG8gdml6dWFsaXpvdmHFpSBqZWRubyBzw7podmV6ZGllLg0KU2vDunNtZSB0byBzcHJhdmnFpSBwcmUgdsWhZXRreSB6dm9sZW7DqSBzw7podmV6ZGlhIHpvIHpuYW1lbsOtIHp2ZXJva3J1aHUuIEFrIHZvbMOtbWUgZmF6ZXRvdsOpIHpvYnJhemVuaWUsIGplIG51dG7DqSBuYXN0YXZpxaUgcGFyYW1ldGVyIHNjYWxlcyBha28gdm/Evm7DvSwgcHJldG/FvmUgaW5hayBieSBzbWUgbmV2aWRlbGkgbmnEjSAoemzDoSBtaWVya2EpLg0KDQpgYGB7cn0NCmh5Z2RhdGFfMl92aV96DQpnZ3Bsb3QoZGF0YSA9IGh5Z2RhdGFfMl92aV96KSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gaHlnZGF0YV8yX3ZpX3okcmFyYWQsIHkgPSBoeWdkYXRhXzJfdmlfeiRkZWNyYWQsIHNpemUgPSAxLzEwMF4oaHlnZGF0YV8yX3ZpX3okbWFnKSwgYWxwaGEgPSAxKSwgY29sb3VyID0gImJsYWNrIiwgYmFja2dyb3VuZD0yKSArIA0KZmFjZXRfd3JhcCh+Y29uLHNjYWxlcyA9ICJmcmVlIikgKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnd2hpdGUnLCBjb2xvdXIgPSAnd2hpdGUnKSkNCmBgYA0KDQogIE5pZWt0b3LDqSBzw7podmV6ZGlhIHPDuiByb3pwb3puYXRlxL5uw6kgbGVwxaFpZSwgaW7DqSBob3LFoWllLiBEYWxvIGJ5IHNhIHRvIHpsZXDFoWnFpSBuYXByw61rbGFkIGluw71tIG5hc3RhdmVuw61tIGZpbHRyYcSNbsOpaG8gcGFyYW1ldHJhIG1hZ25pdMO6ZHkgcHJlIGthxb5kw6kgc8O6aHZlemRpZSwgcG9kxL5hIHBvxI10dSBodmllemQuIE5pZWt0b3LDqSBzw7podmV6ZGlhIHRvdGnFviBvYnNhaHVqw7ogYWogaHZpZXpkeSBzIG1lbsWhb3UgbWFnbml0w7pkb3UsIGt0b3LDqSBzw7ogYWxlIHbDvXpuYcSNbsOpIHByZSBpZGVudGlmaWvDoWNpdSB0dmFydS4NCiAgTXkgc2EgdsWhYWsgZcWhdGUgcG96cmllbWUgbmEgxI9hbMWhaXUgY2hhcmFrdGVyaXN0aWt1LiBQb3pyaWVtZSBzYSwgYWtvIGJ1ZMO6IHRpZXRvIHPDumh2ZXpkaWEgdnl6ZXJhxaUgbyAxMCAwMDAgcm9rb3YuIFRha8O9dG8gcG9zdW4gbcO0xb5lbWUgdml6dWFsaXpvdmHFpSBuYSB6w6FrbGFkZSByYWRpw6FsbnljaCByw71jaGxvc3TDrSB6YSByb2ssIGt0b3LDqSBzw7ogdGFrdGllxb4gcHLDrXRvbW7DqSB2IGRhdGFiw6F6ZS4gVGFrxb5lIHZ5dcW+aW1lIGZ1bmtjaWUgYmFsw61rYSBkcGx5cjoNCg0KYGBge3J9DQpoeWdkYXRhXzJfdmlfeg0KaHlnZGF0YV8yX3ZpX3ogPC0gKG11dGF0ZShoeWdkYXRhXzJfdmlfeiwgcmFyYWRfMTBrID0gMTAwMDAwKnBtcmFyYWQgKyByYXJhZCwgZGVjcmFkXzEwayA9IDEwMDAwMCpwbWRlY3JhZCArIGRlY3JhZCApKQ0KYGBgDQoNCg0KICBUZXJheiB1xb4gem9zdMOhdmEgdHZhciBzw7podmV6ZMOtIG8gMTAwIDAwMCByb2tvdiBsZW4gdnlrcmVzbGnFpS4gKG5lemFiw7pkYW1lLCDFvmUgamUgdG8gcHJpIHV2YcW+b3ZhbmVqIGtvbsWhdGFudG5laiByw71jaGxvc3RpIHBvaHlidSBha28gYWogbWFnbml0w7pkZSwgxI1vIG5pZSBqZSBwcmF2aWRsb20pOg0KDQoNCmBgYHtyfQ0KaHlnZGF0YV8yX3ZpX3oNCmdncGxvdChkYXRhID0gaHlnZGF0YV8yX3ZpX3opICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBoeWdkYXRhXzJfdmlfeiRyYXJhZF8xMGssIHkgPSBoeWdkYXRhXzJfdmlfeiRkZWNyYWRfMTBrLCBzaXplID0gMS8xMF4oaHlnZGF0YV8yX3ZpX3okbWFnKSwgYWxwaGEgPSAxKSwgY29sb3VyID0gImJsYWNrIiwgYmFja2dyb3VuZD0yKSArIA0KZmFjZXRfd3JhcCh+Y29uLHNjYWxlcyA9ICJmcmVlIikgKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnd2hpdGUnLCBjb2xvdXIgPSAnd2hpdGUnKSkNCmBgYA0KDQogIFRha3RvIGJ1ZMO6IG5hxaFlIHPDumh2ZXpkaWEgdnl6ZXJhxaUgbyAxMDAgMDAwIHJva292LiBUdmFyIG5pZWt0b3LDvWNoIHpvc3RhbmUgZcWhdGUgcm96cG96bmF0ZcS+bsO9LCB6YXRpYcS+IMSNbyB1IGluw71jaCBidWRlIGRlZm9ybW92YW7DvS4gKFByaSBwYXJhbWV0cmkgMSAwMDAgMDAwIHJva292IHXFviBzw7ogc8O6aHZlemRpYSBuZXJvenBvem5hdGXEvm7DqSkNCg0KICBWIHRlanRvIHByw6FjaSBzbWUgc2EgcG9rw7pzaWxpIHZ5dcW+acWlIHByb2dyYW1vdmFjw60gamF6eWsgUiBuYSBvcmdhbml6w6FjaXUgYSB2aXp1YWxpesOhY2l1IGTDoXQuIFphbWVyYWxpIHNtZSBzYSBwcsOhdmUgbmEgdGlldG8gZHZlIG9ibGFzdGksIHByZXRvxb5lIGlkZSBvIG5hasSNYXN0ZWrFoWllIHBvdcW+w612YW7DqSB0eXB5IHByw6FjZSBzIGTDoXRhbWkuIA0KICBWIHBydm9tIG5hxaFvbSBrb25rcsOpdG5vbSBwcsOtcGFkZSBzbWUgZm9ybXVsb3ZhbGkgaHlwb3TDqXp1IG8gdnrFpWFodSBtYWduaXTDumR5IGEgdnpkaWFsZW5vc3RpIGh2aWV6ZHksIGt0b3LDuiBzbWUgcG8gcHJldXNwb3JpYWRhbsOtIGTDoXQgYSBpY2ggdnlrcmVzbGVuw60gdXByYXZpbGkuIERva8OhemFsaSBzbWUgdGFrLCDFvmUgdml6dWFsaXrDoWNpYSBhIG9yZ2FuaXrDoWNpYSBkw6F0IGplIHZlxL5taSBkw7RsZcW+aXTDoSBwcmUgc2Zvcm11bG92YW5pZS9wb3R2cmRlbmllL3Z5dnLDoXRlbmllIHZlZGVja2VqIGh5cG90w6l6eS4NCiAgViBkcnVoZWogc2vDtHIgesOhYmF2bmVqIMSNYXN0aSBzbWUgc2EgdmVub3ZhbGkgdnlrcmVzxL5vdmFuaXUgemRhbmxpdmVqIHBvbG9oeSBodmllemQgbmEgb2Jsb2hlIHBvZMS+YSBzw7podmV6ZMOtLiBacmVkdWtvdmFsaSBzbWUgdsO9c3R1cHkgeiBkYXRhYsOhenksIMSNbyBuw6FtIHVtb8W+bmlsbyByb3p1bW5lIHZpenVhbGl6b3ZhxaUgZMOhdGEuIFByaWRhbm91IGhvZG5vdG91IGJvbGEgcHJvZ27Ds3phLCBrdG9yw6Egc27DocSPIGJ1ZMO6Y2ltIGFzdHJvbsOzbW9tIHXEvmFoxI3DrSBvcmllbnTDoWNpdSBuYSBvYmxvaGUuIDopIA0KICBNZXTDs2R5IGJ5IGJvbG8gbW/Fvm7DqSB6bGVwxaFpxaUgcG91xb5pdMOtbSBrb21wbGV4bmVqxaHDrWNoIHBvc3R1cG92LiANCiAg